#include "struct.h"
#include "symbole.h"
#include "tabSymbole.h"
#include "instruction.h"
#include "arbre_evaluation.h"
#include "projet.h"

extern FILE *yyin;

#define NB_LIGNES 10
#define NB_COL 10
#define MAX_FLEURS 10
#define MAX_CARNIVORES 10
/*nombre d'abeilles maximum par ruche*/
#define MAX_ABEILLES 10

/*servira a determiner le temps pendant lequel dormira un thread (en millisecondes)*/
#define TEMPS_SLEEP	99999
/*Plus la valeur est grande, moins il y aura de fourmis sur la grille*/
#define RAND_VAL_MAX	20


#define MAX_NECTAR 10
#define INIT_NECTAR 100


#define COUT_ABEILLE 10
#define COUT_MIEL 10

/*défini les attentes en fonction de la vitesse d'une abeille
par exemple si ATT_X = 5, l'attente = (10-vitesse)/5+1 soit 1 ou 2*/
#define ATT_MVT 5
#define ATT_BUT 2
#define ATT_REC 5
#define ATT_DEC 5
#define ATT_ATQ 2

#define ab 0
#define mi 1

// définir un tableau de fleur dont l'id est l'indice du tableau pour retrouver la fleur
// l'emplacement de la fleur est stockée dans la case
// permet de récupérer le nectar d'une fleur sans les coordonnées de la case

serveurAff_t serveurAff = {1, 0, 0, 0, PTHREAD_MUTEX_INITIALIZER,
							PTHREAD_COND_INITIALIZER,PTHREAD_COND_INITIALIZER};

case_t grille[NB_COL][NB_LIGNES];
fleur * fleurs[MAX_FLEURS];
carnivore * carnivores[MAX_CARNIVORES];
abeille * abeilles[MAX_ABEILLES*2];
ruche * ruches[2];
algo * list_algo;
int cptFleurs = 0;
int cptCarnivores = 0;
int nb_algo = 0;
int creation_thread = 0;
pthread_mutex_t mutex_creation_abeille = PTHREAD_MUTEX_INITIALIZER;

void case_ajoutAbeille(int x, int y,abeille * a){
	//printf("x : %d, y : %d, element  : %d\n",x,y,grille[x][y].element);
	if(grille[x][y].element==GRILLE_VIDE){
		grille[x][y].element=GRILLE_ABEILLE;
	}
	liste_abeille * l =(liste_abeille *)malloc(sizeof(struct liste_abeille));
	l->suivante=(grille[x][y].liste_abeille);
	l->abeille=a;
	grille[x][y].liste_abeille=l;
	grille[x][y].qte_abeilles++;
	//printf("case_ajoutAbeille termine   nouvel element de la case : %d qte_abeille : %d\n",grille[x][y].element,grille[x][y].qte_abeilles);
}

void case_supprimerAbeille(int x,int y,abeille * a){
	//printf("case_supprimerAbeille posx : %d, posy : %d, element :%d\n",x,y,grille[x][y].element);
	int trouve=0;
	
	
	liste_abeille * l =(liste_abeille *)grille[x][y].liste_abeille;
	
	if (l->abeille->num==a->num){
		trouve==1;
		grille[x][y].qte_abeilles--;
		grille[x][y].liste_abeille=l->suivante;
		free(l);
		if (grille[x][y].qte_abeilles==0 && grille[x][y].element==GRILLE_ABEILLE){
			grille[x][y].element=GRILLE_VIDE;
		}		
	}else {
		liste_abeille * temp =(grille[x][y].liste_abeille);
		while(l->suivante!=NULL && trouve ==0){
			if (l->suivante->abeille->num==a->num){
				if (l->suivante->suivante==NULL){
					free(l->suivante);
					l->suivante=NULL;
					grille[x][y].qte_abeilles--;
					}
				else{
					temp=l->suivante->suivante;
					free(l->suivante);
					l->suivante=temp;
					grille[x][y].qte_abeilles--;
				}	
				trouve=1;
			}
			l=l->suivante;
		}
	}

	
	
	
}



void avancer(abeille *a){
	// verrouiller le case courante (bloquant)
		pthread_mutex_lock(& (grille[a->posx][a->posy].mutex));
		
		int n_x, n_y, a_x, a_y;
		int deplacement;
		a_x = a->posx;
		a_y = a->posy;
		
		// déplacement
		do {
			
			deplacement = rand() % 4;
			switch (deplacement) {
				case 0:
					// Gauche
					n_x = (a->posx)-1;
					n_y = a->posy;
					break;
				
				case 1:
					// Haut
					n_x = a->posx;
					n_y = a->posy-1;
					break;
				
				case 2:
					// Droite
					n_x = (a->posx)+1;
					n_y = a->posy;
					break;
				case 3:
					// Bas
					n_x = a->posx;
					n_y = (a->posy)+1;
					break;
			}
			//printf("n_x : %d, n_y : %d\n",n_x,n_y);
		}while(n_x>=NB_COL || n_y>=NB_LIGNES || n_x<0 || n_y<0);
		
		
			
		pthread_mutex_lock(& (grille[n_x][n_y].mutex));
		switch (grille[n_x][n_y].element) {		
			case GRILLE_CARNIVORE:		
				// Déplacer l'abeille sur la case souhaitée
				case_ajoutAbeille(n_x,n_y,a);
				case_supprimerAbeille(a->posx,a->posy,a);
				
				a->posx = n_x;
				a->posy = n_y;
				
				printf("L'abeille %d est piégée\n",a->num);
				pthread_mutex_lock(&serveurAff.mutex);
				while (!serveurAff.fin)
					pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
				serveurAff.reqATraiter = 1;
				serveurAff.fin = 0;
				pthread_cond_signal(&serveurAff.requete);
				pthread_mutex_unlock(&serveurAff.mutex);
				
				pthread_mutex_unlock(& (grille[n_x][n_y].mutex));
				pthread_mutex_unlock(& (grille[a_x][a_y].mutex));
				
				pthread_mutex_lock(& (carnivores[grille[n_x][n_y].car]->mutex));
				carnivore * c = carnivores[grille[n_x][n_y].car];
				c->qte_abeille++;
				int compteur=0;
				while (compteur<(10-(a->vitesse)) && c->qte_abeille<3){
					printf("l'abeille %d est toujours piégée\n",a->num);
					pthread_mutex_unlock(& (carnivores[grille[n_x][n_y].car]->mutex));
					sleep(1);
					pthread_mutex_lock(&a->mutex);
					a->energie=a->energie-2;
					pthread_mutex_unlock(&a->mutex);
					compteur++;
					pthread_mutex_lock(& (carnivores[grille[n_x][n_y].car]->mutex));
				}
				if (c->qte_abeille==3){
					c->qte_abeille=0;
					printf("l'abeille %d (vie : %d) est sortie du piège au bout de %dsec car la plante carnivore a capturé 3 abeilles",a->num,a->energie,compteur);
				}
				else{
					c->qte_abeille--;
					printf("l'abeille %d (vie : %d) est sortie du piège au bout de %dsec, sa vitesse est : %d\n",a->num,a->energie,compteur,a->vitesse);
				
				}
				pthread_mutex_unlock(& (carnivores[grille[n_x][n_y].car]->mutex));
				
				avancer(a);
				break;
			default:	
				// Déplacer l'abeille sur la case souhaitée
				case_ajoutAbeille(n_x,n_y,a);
				case_supprimerAbeille(a->posx,a->posy,a);
				
				a->posx = n_x;
				a->posy = n_y;
				
				printf("L'abeille %d a avancer\n",a->num);
				pthread_mutex_lock(&serveurAff.mutex);
				while (!serveurAff.fin)
					pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
				serveurAff.reqATraiter = 1;
				serveurAff.fin = 0;
				pthread_cond_signal(&serveurAff.requete);
				pthread_mutex_unlock(&serveurAff.mutex);
				
				pthread_mutex_unlock(& (grille[n_x][n_y].mutex));
				pthread_mutex_unlock(& (grille[a_x][a_y].mutex));
				break;
			}		
			
		
}

 void deplacer(int x,int y, abeille *a){
	while (x!=a->posx){
		// verrouiller le case courante (bloquant)
		pthread_mutex_lock(& (grille[a->posx][a->posy].mutex));
		
		int n_x, n_y, a_x, a_y;
		
		

		a_x = a->posx;
		a_y = a->posy;
		
		if (x<a->posx){
			// Gauche
			n_x = (a->posx)-1;
			n_y = a->posy;
		}
		else {
			// Droite
			n_x = (a->posx)+1;
			n_y = a->posy;
		}
				
			
		pthread_mutex_lock(& (grille[n_x][n_y].mutex));
		switch (grille[n_x][n_y].element) {		
			case GRILLE_CARNIVORE:		
				// Déplacer l'abeille sur la case souhaitée
				case_ajoutAbeille(n_x,n_y,a);
				case_supprimerAbeille(a->posx,a->posy,a);
				
				a->posx = n_x;
				a->posy = n_y;
				
				printf("L'abeille %d est piégée\n",a->num);
				pthread_mutex_lock(&serveurAff.mutex);
				while (!serveurAff.fin)
					pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
				serveurAff.reqATraiter = 1;
				serveurAff.fin = 0;
				pthread_cond_signal(&serveurAff.requete);
				pthread_mutex_unlock(&serveurAff.mutex);
				
				pthread_mutex_unlock(& (grille[n_x][n_y].mutex));
				pthread_mutex_unlock(& (grille[a_x][a_y].mutex));
				
				pthread_mutex_lock(& (carnivores[grille[n_x][n_y].car]->mutex));
				carnivore * c = carnivores[grille[n_x][n_y].car];
				c->qte_abeille++;
				int compteur=0;
				while (compteur<(10-(a->vitesse)) && c->qte_abeille<3){
					printf("l'abeille %d est toujours piégée\n",a->num);
					pthread_mutex_unlock(& (carnivores[grille[n_x][n_y].car]->mutex));
					sleep(1);
					pthread_mutex_lock(&a->mutex);
					a->energie=a->energie-2;
					pthread_mutex_unlock(&a->mutex);
					compteur++;
					pthread_mutex_lock(& (carnivores[grille[n_x][n_y].car]->mutex));
				}
				if (c->qte_abeille==3){
					c->qte_abeille=0;
					printf("l'abeille %d (vie : %d) est sortie du piège au bout de %dsec car la plante carnivore a capturé 3 abeilles",a->num,a->energie,compteur);
				}
				else{
					c->qte_abeille--;
					printf("l'abeille %d (vie : %d) est sortie du piège au bout de %dsec, sa vitesse est : %d\n",a->num,a->energie,compteur,a->vitesse);
				
				}
				pthread_mutex_unlock(& (carnivores[grille[n_x][n_y].car]->mutex));
				
				deplacer(x,y,a);
				break;
			default:	
				// Déplacer l'abeille sur la case souhaitée
				case_ajoutAbeille(n_x,n_y,a);
				case_supprimerAbeille(a->posx,a->posy,a);
				
				a->posx = n_x;
				a->posy = n_y;
				
				printf("Déplacer(%d,%d) actuellement en (%d,%d) avec l'abeille %d (vitesse : %d) tps : %d\n",x,y,a->posx,a->posy,a->num,a->vitesse,(10-a->vitesse)/ATT_MVT +1);
				pthread_mutex_lock(&serveurAff.mutex);
				while (!serveurAff.fin)
					pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
				serveurAff.reqATraiter = 1;
				serveurAff.fin = 0;
				pthread_cond_signal(&serveurAff.requete);
				pthread_mutex_unlock(&serveurAff.mutex);
				
				pthread_mutex_unlock(& (grille[n_x][n_y].mutex));
				pthread_mutex_unlock(& (grille[a_x][a_y].mutex));
				break;
			}	
			sleep((10-a->vitesse)/ATT_MVT +1);	
	}
	while (y!=a->posy){
		// verrouiller le case courante (bloquant)
		pthread_mutex_lock(& (grille[a->posx][a->posy].mutex));
		
		int n_x, n_y, a_x, a_y;

		a_x = a->posx;
		a_y = a->posy;
		
		if (y<a->posy){
			// Haut
			n_x = a->posx;
			n_y = a->posy-1;
		}
		else {
			// Bas
			n_x = a->posx;
			n_y = a->posy+1;
		}
				
			
		pthread_mutex_lock(& (grille[n_x][n_y].mutex));
		switch (grille[n_x][n_y].element) {		
			case GRILLE_CARNIVORE:		
				// Déplacer l'abeille sur la case souhaitée
				case_ajoutAbeille(n_x,n_y,a);
				case_supprimerAbeille(a->posx,a->posy,a);
				
				a->posx = n_x;
				a->posy = n_y;
				
				printf("L'abeille %d est piégée\n",a->num);
				pthread_mutex_lock(&serveurAff.mutex);
				while (!serveurAff.fin)
					pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
				serveurAff.reqATraiter = 1;
				serveurAff.fin = 0;
				pthread_cond_signal(&serveurAff.requete);
				pthread_mutex_unlock(&serveurAff.mutex);
				
				pthread_mutex_unlock(& (grille[n_x][n_y].mutex));
				pthread_mutex_unlock(& (grille[a_x][a_y].mutex));
				
				pthread_mutex_lock(& (carnivores[grille[n_x][n_y].car]->mutex));
				carnivore * c = carnivores[grille[n_x][n_y].car];
				c->qte_abeille++;
				int compteur=0;
				while (compteur<(10-(a->vitesse)) && c->qte_abeille<3){
					printf("l'abeille %d est toujours piégée\n",a->num);
					pthread_mutex_unlock(& (carnivores[grille[n_x][n_y].car]->mutex));
					sleep(1);
					pthread_mutex_lock(&a->mutex);
					a->energie=a->energie-2;
					pthread_mutex_unlock(&a->mutex);
					compteur++;
					pthread_mutex_lock(& (carnivores[grille[n_x][n_y].car]->mutex));
				}
				if (c->qte_abeille==3){
					c->qte_abeille=0;
					printf("l'abeille %d (vie : %d) est sortie du piège au bout de %dsec car la plante carnivore a capturé 3 abeilles",a->num,a->energie,compteur);
				}
				else{
					c->qte_abeille--;
					printf("l'abeille %d (vie : %d) est sortie du piège au bout de %dsec, sa vitesse est : %d\n",a->num,a->energie,compteur,a->vitesse);
				
				}
				pthread_mutex_unlock(& (carnivores[grille[n_x][n_y].car]->mutex));
				
				deplacer(x,y,a);
				break;
			default:	
				// Déplacer l'abeille sur la case souhaitée
				case_ajoutAbeille(n_x,n_y,a);
				case_supprimerAbeille(a->posx,a->posy,a);
				
				a->posx = n_x;
				a->posy = n_y;
				
				printf("Déplacer(%d,%d) actuellement en (%d,%d) avec l'abeille %d (vitesse : %d) tps : %d\n",x,y,a->posx,a->posy,a->num,a->vitesse,(10-a->vitesse)/ATT_MVT +1);
				pthread_mutex_lock(&serveurAff.mutex);
				while (!serveurAff.fin)
					pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
				serveurAff.reqATraiter = 1;
				serveurAff.fin = 0;
				pthread_cond_signal(&serveurAff.requete);
				pthread_mutex_unlock(&serveurAff.mutex);
				
				pthread_mutex_unlock(& (grille[n_x][n_y].mutex));
				pthread_mutex_unlock(& (grille[a_x][a_y].mutex));
				break;
			}
			sleep((10-a->vitesse)/ATT_MVT +1);
	}
	pthread_mutex_lock(&serveurAff.mutex);
	while (!serveurAff.fin)
		pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
	serveurAff.reqATraiter = 1;
	serveurAff.fin = 0;
	pthread_cond_signal(&serveurAff.requete);
	pthread_mutex_unlock(&serveurAff.mutex);
	sleep((10-a->vitesse)/ATT_MVT +1);
}

void butiner(abeille * a){

	printf("-------------------------\n TOTOTOOTOTOTOT \n-----------------");

	if (grille[a->posx][a->posy].element==GRILLE_FLEUR){
		pthread_mutex_lock(&a->mutex);
		pthread_mutex_lock(&fleurs[grille[a->posx][a->posy].fl]->mutex);
		fleur *f =(fleur *)fleurs[grille[a->posx][a->posy].fl];
		if (f->estlibre){ /*si la fleur est libre*/
			f->estlibre=0;
			while(f->nectar>0 && a->nectarmax>a->nectar){
				/*on butine*/
				/*modification des attribut*/
				f->nectar--;
				a->nectar++;
				/*on déverrouille*/
				pthread_mutex_unlock(&fleurs[grille[a->posx][a->posy].fl]->mutex);
				pthread_mutex_unlock(&a->mutex);
				/*on attend un peu*/
				sleep((10-a->vitesse)/ATT_BUT+1);
				/*on reverrouille pour l'itération suivante*/
				pthread_mutex_lock(&a->mutex);
				pthread_mutex_lock(&fleurs[grille[a->posx][a->posy].fl]->mutex);
				
			}
			f->estlibre=1;
			pthread_mutex_unlock(&fleurs[grille[a->posx][a->posy].fl]->mutex);
			pthread_mutex_unlock(&a->mutex);
			printf("L'abeille %d (nect : %d) a butiner une fleur (%d,%d) (nect : %d)\n",a->num, a->nectar, a->posx,a->posy,f->nectar);
		}
		else{
			pthread_mutex_unlock(&fleurs[grille[a->posx][a->posy].fl]->mutex);
			pthread_mutex_unlock(&a->mutex);
			printf("L'abeille %d a tenté de butiner une fleur (%d,%d) occupé \n",a->num, a->posx,a->posy);

		}	
		
		
		
		
		
	}else{
		printf("L'abeille %d tenté de butiner une fleur inexistante (%d,%d)\n",a->num, a->posx,a->posy);

	}
	
	pthread_mutex_lock(&serveurAff.mutex);
	while (!serveurAff.fin)
		pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
	serveurAff.reqATraiter = 1;
	serveurAff.fin = 0;
	pthread_cond_signal(&serveurAff.requete);
	pthread_mutex_unlock(&serveurAff.mutex);
	
	sleep((10-a->vitesse)/ATT_BUT+1);
}


void recharger(abeille * a){
	int recharge=0;
	if (a->posx==a->ruchex && a->posy == a->ruchey){
		pthread_mutex_lock(&a->mutex);
		pthread_mutex_lock(&ruches[a->num_ruche]->mutex);
		ruche *r =(ruche *)ruches[a->num_ruche];
		
		while(r->qte_miel>0 && a->energiemax > a->energie){
			/*on recharge*/
			recharge=1;
			/*modification des attribut*/
			r->qte_miel--;
			if(a->energie+5 > a->energiemax){
				a->energie=a->energiemax;
			}
			else{
				a->energie=a->energie+5;
			}
			/*on déverrouille*/
			pthread_mutex_unlock(&a->mutex);
			pthread_mutex_unlock(&ruches[a->num_ruche]->mutex);
			/*on attend un peu*/
			sleep((10-a->vitesse)/ATT_REC+1);
			/*on reverrouille pour l'itération suivante*/
			pthread_mutex_lock(&a->mutex);
			pthread_mutex_lock(&ruches[a->num_ruche]->mutex);
			
		}
		
		if (recharge==1){
			printf("L'abeille %d a rechargé son energie (%d), miel restant : %d\n",a->num, a->energie, r->qte_miel);
		}
		else{
			printf("L'abeille %d n'a pas rechargé son energie (miel inexistant ou energie déjà au max)\n",a->num);
		}
		pthread_mutex_unlock(&a->mutex);
		pthread_mutex_unlock(&ruches[a->num_ruche]->mutex);
				
		
	}else{
		printf("L'abeille %d n'est pas sur sa ruche\n",a->num);

	}
	
	pthread_mutex_lock(&serveurAff.mutex);
	while (!serveurAff.fin)
		pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
	serveurAff.reqATraiter = 1;
	serveurAff.fin = 0;
	pthread_cond_signal(&serveurAff.requete);
	pthread_mutex_unlock(&serveurAff.mutex);
	
	sleep((10-a->vitesse)/ATT_REC+1);
}

void decharger(abeille * a){
	int decharge=0;
	if (a->posx==a->ruchex && a->posy == a->ruchey){
		pthread_mutex_lock(&a->mutex);
		pthread_mutex_lock(&ruches[a->num_ruche]->mutex);
		ruche *r =(ruche *)ruches[a->num_ruche];
		
		while(a->nectar>0){
			/*on decharge*/
			decharge=1;
			/*modification des attribut*/
			r->qte_nectar++;
			a->nectar--;
			/*on déverrouille*/
			pthread_mutex_unlock(&a->mutex);
			pthread_mutex_unlock(&ruches[a->num_ruche]->mutex);
			/*on attend un peu*/
			sleep((10-a->vitesse)/ATT_DEC+1);
			/*on reverrouille pour l'itération suivante*/
			pthread_mutex_lock(&a->mutex);
			pthread_mutex_lock(&ruches[a->num_ruche]->mutex);
			
		}
		
		if (decharge==1){
			printf("L'abeille %d a dechargé son nectar (%d), nectar présent dans la ruche : %d\n",a->num, a->nectar, r->qte_nectar);
		}
		else{
			printf("L'abeille %d n'a pas de nectar à décharger\n",a->num);
		}
		pthread_mutex_unlock(&a->mutex);
		pthread_mutex_unlock(&ruches[a->num_ruche]->mutex);
				
		
	}else{
		printf("L'abeille %d n'est pas sur sa ruche\n",a->num);

	}
	
	pthread_mutex_lock(&serveurAff.mutex);
	while (!serveurAff.fin)
		pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
	serveurAff.reqATraiter = 1;
	serveurAff.fin = 0;
	pthread_cond_signal(&serveurAff.requete);
	pthread_mutex_unlock(&serveurAff.mutex);
	
	sleep((10-a->vitesse)/ATT_DEC+1);
}

abeille * recherche_ennemie(liste_abeille * l,int num_rucheAmi){
	if (l->abeille->num_ruche!=num_rucheAmi){
		return l->abeille;
	}
	while(l->suivante->abeille!=NULL){
		if (num_rucheAmi==0){
			if (l->suivante->abeille->num_ruche==1){
				return l->suivante->abeille;
			}
			else{
				l=l->suivante;
			}
		}
		else{
			if (l->suivante->abeille->num_ruche==0){
				return l->suivante->abeille;
			}
			else{
				l=l->suivante;
			}
		}
	}
	return NULL;
}

void attaquer(abeille *a ){
	liste_abeille * l = (liste_abeille *) grille[a->posx][a->posy].liste_abeille;
	
	

	abeille * e = (abeille *)recherche_ennemie(l,a->num_ruche);

	
	
	

	
	if (e!=NULL){
		pthread_mutex_lock(&a->mutex);
		pthread_mutex_lock(&e->mutex);
		if (abeilles[e->num]!=NULL){
			
			int att = rand()%(a->attaque);
			int def = rand()%(e->defense);
			if (att>def){
			
				e->energie=e->energie-(att-def);
			
				printf("L'abeille %d (attaque : %d) a attaqué l'abeille %d (energie : %d, def : %d) sur la case (%d,%d)\n",a->num, a->attaque,e->num,e->energie,e->defense,a->posx,a->posy);
			}
			else{
				printf("L'abeille %d (attaque : %d) a échoué son attaque sur l'abeille %d (energie : %d, def : %d) sur la case (%d,%d)\n",a->num, a->attaque,e->num,e->energie,e->defense,a->posx,a->posy);
			}
			
		}
		
		pthread_mutex_unlock(&a->mutex);
		pthread_mutex_unlock(&e->mutex);
	}
	else{
		printf("L'abeille %d n'a pas trouvé d'ennemie dans la case (%d,%d)\n",a->num,a->posx,a->posy);
		

	}
	
	
		
	pthread_mutex_lock(&serveurAff.mutex);
	while (!serveurAff.fin)
		pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
	serveurAff.reqATraiter = 1;
	serveurAff.fin = 0;
	pthread_cond_signal(&serveurAff.requete);
	pthread_mutex_unlock(&serveurAff.mutex);
	printf("-----------------------tps attente---%d\n",(10-(a->vitesse))/ATT_ATQ+1);
	sleep((10-(a->vitesse))/ATT_ATQ+1);
	
}

void exec_instruction(instruction * i,abeille * a) {
	//printf("\n\n------------- DEBUT PARCOURS ------------- \n");
	
	//printf("\n\n%d\n\n",i->suivante->suivante->suivante->type_instruction);
	
	while(i!=NULL) {
		pthread_mutex_lock(&a->mutex);
		if (a->energie <= 0 || a->duree_vie <=0){
			printf ("L'abeille %d est morte\n",a->num);
			case_supprimerAbeille(a->posx,a->posy,a);
			abeilles[a->num]=NULL;
			pthread_mutex_unlock(&a->mutex);
			free(a);
			pthread_mutex_lock(&serveurAff.mutex);
			serveurAff.cptAbeilles--;
			while (!serveurAff.fin)
				pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
			serveurAff.reqATraiter = 1;
			serveurAff.fin = 0;
			pthread_cond_signal(&serveurAff.requete);
			pthread_mutex_unlock(&serveurAff.mutex);
	
	sleep((10-a->vitesse)/ATT_ATQ+1);
			pthread_exit(NULL);
		}
		pthread_mutex_unlock(&a->mutex);
		
		switch(i->type_instruction){
			case INSCTRUCTION_ACTION :
				switch((int)i->s->valeur){
					case ACTION_BUTINER:
						printf("Butiner()\n");
						butiner(a);
						break;
					case ACTION_RECHARGER:
						printf("Recharger()\n");
						recharger(a);
						break;
					case ACTION_DECHARGER:
						printf("Decharger()\n");
						decharger(a);
						break;
					case ACTION_ATTAQUER:
						printf("Attaquer() par abeille %d\n",a->num);
						attaquer(a);
						break;
					case ACTION_AVANCER:
						printf("Avancer() avec l'abeille %d (vitesse : %d) tps : %d\n",a->num,a->vitesse,(10-a->vitesse)/ATT_MVT +1);
						avancer(a);
						sleep((10-a->vitesse)/ATT_MVT +1);
						break;
					case ACTION_DEPLACER:
						deplacer(evaluer_arbre(i->condition1,a,fleurs,grille),evaluer_arbre(i->condition2,a,fleurs,grille),a);
						break;
				}
				break;
				
			case INSCTRUCTION_VAR :
				if(i->s->type == SYMBOLE_VARIABLE_USER) {
					//printf("--VARIABLE USER -- :");
					//affiche_arbre(i->condition1, a, fleurs, grille);
					//printf("\n");
					i->s->valeur = i->condition1;
				}else {
					if(strcmp(i->s->nom,"ENERGIE")==0)
						a->energie = evaluer_arbre(i->condition1, a, fleurs, grille);
					if(strcmp(i->s->nom,"NECTAR")==0)
						a->nectar = evaluer_arbre(i->condition1, a, fleurs, grille);
					if(strcmp(i->s->nom,"MEMX")==0)
						a->memx = evaluer_arbre(i->condition1, a, fleurs, grille);
					if(strcmp(i->s->nom,"MEMY")==0)
						a->memy = evaluer_arbre(i->condition1, a, fleurs, grille);
					if(strcmp(i->s->nom,"RUCHEX")==0)
						a->ruchex = evaluer_arbre(i->condition1, a, fleurs, grille);
					if(strcmp(i->s->nom,"RUCHEY")==0)
						a->ruchey = evaluer_arbre(i->condition1, a, fleurs, grille);
				}

				break;
				
			case INSCTRUCTION_COND :
				switch(i->type_action_cond){
					case ACTION_COND_SI :
						if(evaluer_arbre(i->condition1, a, fleurs, grille)==1){
							exec_instruction(i->list1->suivante, a);
						}
						break;
						
					case ACTION_COND_SI_SINON :
						if(evaluer_arbre(i->condition1, a, fleurs, grille)==1){
							exec_instruction(i->list1->suivante, a);
						} else {
							exec_instruction(i->list2->suivante, a);
						}
						break;
						
					case ACTION_COND_SI_SINON_SI :
						if(evaluer_arbre(i->condition1, a, fleurs, grille)==1){
							exec_instruction(i->list1->suivante, a);
						} else if(evaluer_arbre(i->condition2, a, fleurs, grille)==1){
							exec_instruction(i->list2->suivante, a);
						} else {
							exec_instruction(i->list3->suivante, a);
						}
						break;
						
					case ACTION_COND_TANTQUE :
						while(evaluer_arbre(i->condition1, a, fleurs, grille)==1){
							exec_instruction(i->list1->suivante, a);
						}
						break;
				}
				break;
				
			case INSCTRUCTION_FONCTION : 
				/*affiche_arbre(i->condition1);
				printf("(%d)",evaluer_arbre(i->condition1));*/
				break;
		}
	
	//printf("\n---TEST--%d-\n",i->type_instruction);
	
	//if(i->suivante!=NULL)
	i=i->suivante;
	//else
	//	break;
	
	}
}

void *afficherGrille(void *arg) {
	int i, j;
	int fin = 0;
	//printf("afficherGRille");

	serveurAff.cptAbeilles = 0;
	while (!fin) {
		pthread_mutex_lock(&serveurAff.mutex);
		while (!serveurAff.reqATraiter)
			pthread_cond_wait(&serveurAff.requete, &serveurAff.mutex);

		
		printf("Etape %d\n", serveurAff.noEtape);
		printf("Abeilles présentes : %d\n", serveurAff.cptAbeilles);
		printf("Fleurs présentes : %d\n", cptFleurs);
		printf("Plantes Carnivores présentes : %d\n", cptCarnivores);
		printf("Ruche 0 :\n\t Nectar : %d \n\tMiel : %d \n",ruches[0]->qte_nectar, ruches[0]->qte_miel);
		printf("Ruche 1 :\n\t Nectar : %d \n\tMiel : %d \n",ruches[1]->qte_nectar, ruches[1]->qte_miel);
		for (i = 0; i < NB_LIGNES; i++) {
			for (j = 0; j < (NB_COL * 7) + 1; j++)
				printf("-");
			printf("\n");

			for (j = 0; j < NB_COL; j++) {
				printf("|");
				printf(" ");
				switch (grille[j][i].element) {
					case GRILLE_VIDE:
						printf("    ");
						break;
					case GRILLE_FLEUR:
						printf(" Fl ");
						break;
					case GRILLE_CARNIVORE:
						printf(" Ca ");
						break;
					case GRILLE_ABEILLE:
						printf("%dAb%d",grille[j][i].liste_abeille->abeille->num_ruche,grille[j][i].liste_abeille->abeille->num);
						break;
					case GRILLE_RUCHE:
						printf("#R0#");
						break;
					case GRILLE_RUCHEENNEMIE:
						printf("#R1#");
						break;
						
				}
				printf(" ");
			}
			printf("|\n");
		}
		for (i = 0; i < (NB_COL * 7) + 1; i++)
			printf("-");
		printf("\n");
		for (i = 0; i < 4; i++)
			printf("\n");
		usleep(TEMPS_SLEEP);
		serveurAff.noEtape++;
		serveurAff.reqATraiter = 0;
			serveurAff.fin = 1;
		

		pthread_cond_broadcast(&serveurAff.termine);
		pthread_mutex_unlock(&serveurAff.mutex);
	}

	return NULL;
}



void initialiserGrille() {
	int randVal;
	int statut = 0;
	int i, j, ii,jj;


	for (i = 0; i < NB_LIGNES; i++) {
		for (j = 0; j < NB_COL; j++) {
			statut = pthread_mutex_init(&grille[j][i].mutex, NULL);
			grille[j][i].qte_abeilles=0;
			grille[j][i].liste_abeille = (liste_abeille*)malloc(sizeof(liste_abeille));
			randVal = rand() % RAND_VAL_MAX;
			if (randVal > 3)
				randVal = 0;
			else if (randVal==3)
				randVal==1;
			switch (randVal) {
				case GRILLE_VIDE:
					grille[j][i].element = GRILLE_VIDE;
					break;
				case GRILLE_FLEUR:
					if(cptFleurs<MAX_FLEURS){
						grille[j][i].element = GRILLE_FLEUR;
						grille[j][i].fl = cptFleurs;
						fleur * f = (fleur *)malloc(sizeof(struct fleur));
						f->id = cptFleurs;
						f->nectar=100;
						f->estlibre=1;
						fleurs[cptFleurs] = f;
						cptFleurs++;
					}
					break;
				case GRILLE_CARNIVORE:
					if (cptCarnivores<MAX_CARNIVORES){
						grille[j][i].element = GRILLE_CARNIVORE;
						grille[j][i].car = cptCarnivores;
						carnivore * c = (carnivore *)malloc(sizeof(struct carnivore));
						c->id = cptCarnivores;
						c->qte_abeille=0;
						statut = pthread_mutex_init(&c->mutex, NULL);
						carnivores[cptCarnivores] = c;
						cptCarnivores++;
					}
					break;
			}
		}
	}
	
	//création des deux ruches
	
	//calcul distance entre les ruches
	i = rand()%NB_COL;
	j = rand()%NB_LIGNES;
	ii = rand()%NB_COL;
	jj = rand()%NB_LIGNES;
	printf("\n-------%d----------%d---------%d---------%d--------||||%d\n",i,j,ii,jj,(int)sqrt((i-ii)*(i-ii)+(j-jj)*(j-jj)));
	while ((int)sqrt((i-ii)*(i-ii)+(j-jj)*(j-jj))<5 || grille[i][j].element!=GRILLE_VIDE || grille[ii][jj].element!=GRILLE_VIDE){
		i = rand()%NB_LIGNES;
		j = rand()%NB_COL;
		ii = rand()%NB_LIGNES;
		jj = rand()%NB_COL;
		printf("\n------%d----------%d---------%d---------%d--------||||%d\n",i,j,ii,jj,(int)sqrt((i-ii)*(i-ii)+(j-jj)*(j-jj)));
	}

	
	ruche * ra=(ruche*) malloc (sizeof(struct ruche));
	ra->posx=i;
	ra->posy=j;
	ra->qte_nectar=INIT_NECTAR;
	ra->qte_miel=0;
	ra->num_ruche=0;
	ra->qte_abeilles=0;
	ra->thread=(pthread_t *)malloc(sizeof(pthread_t));
	statut = pthread_mutex_init(&ra->mutex, NULL);
	ruches[0]=ra;
	
	grille[ra->posx][ra->posy].element = GRILLE_RUCHE;
	
	printf("----X : %d -----\n",ra->posx);
	printf("----Y : %d -----\n",ra->posy);
	
	ruche * re=(ruche*) malloc (sizeof(struct ruche));
	re->posx=ii;
	re->posy=jj;
	re->qte_nectar=INIT_NECTAR;
	re->qte_miel=0;
	re->num_ruche=1;
	re->qte_abeilles=0;
	re->thread=(pthread_t *)malloc(sizeof(pthread_t));
	statut = pthread_mutex_init(&re->mutex, NULL);
	ruches[1]=re;
	
	grille[re->posx][re->posy].element = GRILLE_RUCHEENNEMIE;
	
	printf("----X : %d -----\n",re->posx);
	printf("----Y : %d -----\n",re->posy);
	
	

}


/* Fonction permettant de créer une abeille
 * Elle prend en paramètre l'id de l'abeille, sa position X et Y
 * et le numéro de la ruche auquel elle doit appartenir
 */
abeille * creer_abeille(int id, int x, int y, int ruche) {
	
	abeille * a = (abeille *) malloc(sizeof(struct abeille));
	a->num = id;
	
	a->energiemax = (rand()%20)+20;
	a->energie = rand()%a->energiemax+1;
	a->nectar = 0;
	a->nectarmax = (rand()%10)+5;
	a->memx = 0;
	a->memy = 0;
	//position courante de l'abeille égale a la position de sa ruche
	a->posx = x;
	a->posy = y;
	a->num_ruche = ruche;
	a->ruchex = x;
	a->ruchey = y;
	a->duree_vie = (rand()%20)+30;
	a->vitesse = rand()%9+1;
	a->attaque = rand()%20;
	a->defense = rand()%25;
	a->thread=(pthread_t *)malloc(sizeof(pthread_t));
	pthread_mutex_init(&a->mutex, NULL);
	int r = rand()%nb_algo;
	algo * temp = list_algo;
	while(r!=0) {
		temp=temp->suivant;
		r--;
	}
	a->algo = temp;
	
	
	
	pthread_mutex_lock(& (grille[a->posx][a->posy].mutex));
	case_ajoutAbeille(a->posx,a->posy,a);
	pthread_mutex_unlock(& (grille[a->posx][a->posy].mutex));
		
				
	return a;	
	
}

void *routineAbeille(void *arg) {
	
	int i=0;
	abeille * a = (abeille *) arg;
	printf("RoutineAbeille  posx : %d, posy : %d\n",a->posx,a->posy);
	symbole * s = (symbole *)rechercher(a->algo->ts,a->algo->nom);	
	while(1){
		printf("iteration %d de l'algo %s avec le symbole %s par l'abeille %d\n",i,a->algo->nom,s->nom,a->num);
		exec_instruction(s->instruction->suivante,a);
		//sleep(2);
		i++;
		/*
			
		// autorise le cancel si le mutex est débloqué
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
		pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
			
		pthread_testcancel();
		*/
		
	}
}

void *dureeVie(void *arg) {
	
	int i;
	while(1){
		for(i=0;i<MAX_ABEILLES*2;i++){
			if(abeilles[i]!=NULL){
				abeilles[i]->duree_vie--;
			}
		}
		sleep(2);
	}
	
}

void *routineRuche(void * arg) {
	int * tmp = (int *)arg;
	int id = *tmp;
	int abeilleOuMiel=ab;
	int isAjout=0;
	printf("Routine de la ruche %d\n",id);
	while(1){
		
		pthread_testcancel();
		
		// proteger le thread en empêchant le cancel dans le mutex
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
		
		int statut = pthread_mutex_trylock(& (ruches[id]->mutex));
		if (statut==0){			
			if (ruches[id]->qte_nectar>=10){
				if (abeilleOuMiel==ab && ruches[id]->qte_abeilles<MAX_ABEILLES){
					/*Création d'une abeille*/

					/*on modifie les valeurs de la ruche*/
					ruches[id]->qte_nectar=ruches[id]->qte_nectar - COUT_ABEILLE;
					ruches[id]->qte_abeilles++;
						
					/*on recherche une case libre dans le tableau d'abeille*/
					pthread_mutex_lock(&mutex_creation_abeille);
					int i=0,trouve=0;
					while(i<MAX_ABEILLES*2 && trouve==0){
						if(abeilles[i]!=NULL){
							i++;
						}
						else{
							trouve=1;
							isAjout=1;
							/*on crée une abeille*/
							abeilles[i]=(abeille *)creer_abeille(i,ruches[id]->posx,ruches[id]->posy,ruches[id]->num_ruche);
							/*on crée le thread abeille*/
							statut = pthread_create(abeilles[i]->thread, NULL, routineAbeille,abeilles[i]);
							printf("Création dans la case %d d'une abeille posx : %d, posy : %d, algo : %s\n",i,abeilles[i]->posx,abeilles[i]->posy,abeilles[i]->algo->nom);
						}
					}
					
					
					pthread_mutex_unlock(&mutex_creation_abeille);					
						
					abeilleOuMiel=mi;	
				}
				else {
					/*on crée du miel*/
					printf("Création de miel\n");
					ruches[id]->qte_miel++;
					ruches[id]->qte_nectar=ruches[id]->qte_nectar - COUT_MIEL;
					abeilleOuMiel=ab;
					isAjout=0;
				}
				printf("qte restante : miel = %d, nectar = %d, abeille = %d\n",ruches[id]->qte_miel,ruches[id]->qte_nectar,ruches[id]->qte_abeilles);
				pthread_mutex_unlock(& ruches[id]->mutex);
				
				/*on lance une requete d'affichage*/
				pthread_mutex_lock(&serveurAff.mutex);
				if (isAjout==1)
					serveurAff.cptAbeilles++;
				while (!serveurAff.fin)
					pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
				serveurAff.reqATraiter = 1;
				serveurAff.fin = 0;
				pthread_cond_signal(&serveurAff.requete);
				pthread_mutex_unlock(&serveurAff.mutex);
			}
			
			if(ruches[id]->qte_nectar<10 && ruches[id]->qte_abeilles==0){
				int ruche_ennemie;
				if(id==0)
					ruche_ennemie=1;
				else
					ruche_ennemie=0;
				
				pthread_cancel(ruches[ruche_ennemie]->thread);
				pthread_exit(NULL);
			}
			
			
			
		}
		
		// autorise le cancel si le mutex est débloqué
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
		pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
		
		pthread_testcancel();

		sleep(1);
	}
}




int main(int argc, char *argv[]) {
	srand(time(NULL));
	
	list_algo = (algo *)malloc(sizeof(struct algo));
	
	printf("-------------------------------------\n");
	printf("-----------------DEBUT---------------\n");
	printf("-------------------------------------\n");
	
	
	 yyin = fopen( argv[1], "r" );
     	yyparse();
    	 printf("---");
     	fclose(yyin);
     
     	algo * temp = list_algo;
     	while(temp->suivant!=NULL){
     		nb_algo++;
     		temp = temp->suivant;
     	}
     
     printf("nombre algo %d",nb_algo);
     
     	int cptAbeilles, i,j;
	pthread_t threadAff, threadVie;
	int statut;
     initialiserGrille();
     for (i = 0; i < NB_LIGNES; i++) {
		for (j = 0; j < NB_COL; j++) {
			printf("%d, ",grille[i][j].element);
		}
		printf("\n");
	}
     
     statut = pthread_create(&threadAff, NULL, afficherGrille, NULL);
     
	//on affiche l'étape 0
     pthread_mutex_lock(&serveurAff.mutex);
     while (!serveurAff.fin)
		pthread_cond_wait(&serveurAff.termine, &serveurAff.mutex);
     serveurAff.reqATraiter = 1;
     serveurAff.fin = 0;
     pthread_cond_signal(&serveurAff.requete);
     pthread_mutex_unlock(&serveurAff.mutex);
     
     sleep(1);
     int * id;
     for (i=0;i<2;i++){
     	id=(int *)malloc(sizeof(int));
     	*id=i;
     	statut = pthread_create(ruches[*id]->thread, NULL, routineRuche,id);
     }
     
     
     
		
     
     creation_thread = 1;
     
     statut = pthread_create(&threadVie, NULL, dureeVie, NULL);
     pthread_join(threadAff, NULL);
     for (i=0;i<2;i++){
     	pthread_join(*(ruches[i]->thread), NULL);
     }
     	

	
	return 0;
	
}
